package com.battle.service.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.battle.pojo.entity.*;
import com.battle.pojo.param.trainingGroup.TrainingPerformanceParam;
import com.battle.pojo.param.trainingSolo.*;
import com.battle.pojo.param.trainingSoloDetails.CreateTrainingSoloDetailsParam;
import com.battle.pojo.param.trainingSoloDetails.CreateTrainingSoloProgramParam;
import com.battle.pojo.vo.trainingSolo.*;
import com.battle.pojo.dto.trainingSolo.*;
import com.battle.service.repository.in.*;
import com.battle.service.service.in.TrainingSoloService;
import lombok.AllArgsConstructor;
import nirvana.core.domains.vo.PageResult;
import nirvana.core.utils.ids.IdGenerator;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;


import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 【描 述】：单人训练服务
 * 【环 境】：J2SE 17
 * 【详 细】：
 */
@Service
@AllArgsConstructor
public class TrainingSoloServiceImpl implements TrainingSoloService {

    private final TrainingSoloRepository trainingSoloRepository;
    private final TrainingSoloDetailsRepository soloDetailsRepository;
    private final UserRepository userRepository;
    private final TrainingProgramRepository programRepository;
    private final TrainingPersonSettingRepository personSettingRepository;
    private final OrganizationRepository organizationRepository;
    private final PersonWarCaseRepository personWarCaseRepository;
    private final UserOrganizationMpRepository userOrganizationMpRepository;
    private final TrainingGroupRepository groupRepository;


    /**
     * 创建单人训练
     *
     * @param param
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createTrainingSolo(CreateTrainingSoloParam param) {
        TrainingSolo trainingSolo = new TrainingSolo();
        BeanUtils.copyProperties(param, trainingSolo);
        Long id = IdGenerator.SNOW.generate();
        trainingSolo.setId(id);

        //部门下所有的人员数量
        Long userNumber = userOrganizationMpRepository.count(
                new LambdaQueryWrapper<>(UserOrganizationMp.class)
                        .eq(UserOrganizationMp::getOrganizationId, param.getDepartmentId())
                        .eq(UserOrganizationMp::getIsDelete, false)
        );

        //不需要训练的人员数量
        Integer settingPersonNumber = 0;
        //查询该部门有多少不需要训练的人员
        List<TrainingPersonSetting> setting = personSettingRepository.getPersonSettingByDepartmentId(param.getDepartmentId());
        if (CollectionUtil.isNotEmpty(setting)) {
            settingPersonNumber = setting.size();
        }

        //应该参加训练的人员=部门下所有的人员数量-不需要训练的人员数量
        Integer shouldPersonNumber = userNumber.intValue() - settingPersonNumber;
        trainingSolo.setShouldTrainingCount(shouldPersonNumber);

        //缺训的人员数量
        Integer absentPersonNumber = 0;
        //缺训人员
        List<Long> absentPersonIds = new ArrayList<>();
        List<AbsentPersonParam> absentPerson = param.getAbsentPerson();
        if (CollectionUtil.isNotEmpty(absentPerson)) {
            String jsonString = JSONArray.toJSONString(absentPerson);
            trainingSolo.setAbsentPerson(jsonString);
            absentPersonNumber = absentPerson.size();

            for (AbsentPersonParam person : absentPerson) {
                absentPersonIds.add(person.getUserId());
            }
        }

        trainingSolo.setAbsentPersonUserIds(JSONArray.toJSONString(absentPersonIds));

        //训练项目
        String programId = JSONArray.toJSONString(param.getProgramIds());
        trainingSolo.setProgramIds(programId);
        trainingSolo.setProgramCount(param.getProgramIds().size());

        //训练类型集合
        List<Integer> typeList = new ArrayList<>();

        //实际参与训练的人员数量
        Integer actualPersonNumber = 0;
        Map<Long, Long> actualPerson = new HashMap<>();

        //完整的项目数量
        Integer completeProgramNumber = 0;
        //合格数量
        Integer qualifiedPersonNumber = 0;
        //不合格数量
        Integer unqualifiedPersonNumber = 0;
        //良好数量
        Integer goodPersonNumber = 0;
        //优秀数量
        Integer excellentPersonNumber = 0;

        //人员对应的训练成绩明细
        List<TrainingSoloDetails> detailsList = new ArrayList<>();
        //训练项目
        List<CreateTrainingSoloProgramParam> programList = param.getProgramParams();
        for (CreateTrainingSoloProgramParam programParam : programList) {
            TrainingProgram program = programRepository.getByIdCheck(programParam.getTrainingProgramId());
            typeList.add(program.getType());

            //人员训练明细
            List<CreateTrainingSoloDetailsParam> trainingSoloDetails = programParam.getTrainingSoloDetails();
            for (CreateTrainingSoloDetailsParam soloDetail : trainingSoloDetails) {
                TrainingSoloDetails details = new TrainingSoloDetails();
                BeanUtils.copyProperties(soloDetail, details);
                actualPerson.put(soloDetail.getUserId(), soloDetail.getUserId());

                //训练项目
                details.setType(program.getType());
                details.setTrainingProgramId(program.getId());

                //单人-队站训练
                details.setTrainingSoleId(trainingSolo.getId());
                details.setStatus(trainingSolo.getStatus());
                details.setTrainingDate(trainingSolo.getTrainingDate());
                details.setDepartmentId(trainingSolo.getDepartmentId());
                details.setTrainingDateType(trainingSolo.getTrainingDateType());
                details.setTrainingPlace(trainingSolo.getTrainingPlace());

                completeProgramNumber = completeProgramNumber + 1;
                //评定结果
                if (soloDetail.getAssessmentResult().equals("达标")) {
                    qualifiedPersonNumber = qualifiedPersonNumber + 1;
                }
                if (soloDetail.getAssessmentResult().equals("不合格")) {
                    unqualifiedPersonNumber = unqualifiedPersonNumber + 1;
                }
                if (soloDetail.getAssessmentResult().equals("良好")) {
                    goodPersonNumber = goodPersonNumber + 1;
                }
                if (soloDetail.getAssessmentResult().equals("优秀")) {
                    excellentPersonNumber = excellentPersonNumber + 1;
                }

                details.setId(IdGenerator.SNOW.generate());
                detailsList.add(details);
            }
        }

        actualPersonNumber = actualPerson.size();
        trainingSolo.setActualTrainingCount(actualPersonNumber);
        trainingSolo.setShouldTrainingCount(shouldPersonNumber);
        trainingSolo.setAbsentTrainingCount(absentPersonNumber);
        trainingSolo.setType(JSONArray.toJSONString(typeList));

        //优秀率=优秀人数/完整的项目数量
        trainingSolo.setExcellentRate(new BigDecimal(0));
        if (completeProgramNumber != 0 && excellentPersonNumber != 0) {
            BigDecimal excellentRate = new BigDecimal(excellentPersonNumber).divide(new BigDecimal(completeProgramNumber), 2, BigDecimal.ROUND_HALF_UP);
            trainingSolo.setExcellentRate(excellentRate);
        }
        //良好率
        if (completeProgramNumber != 0 && goodPersonNumber != 0) {
            BigDecimal goodRate = new BigDecimal(goodPersonNumber).divide(new BigDecimal(completeProgramNumber), 2, BigDecimal.ROUND_HALF_UP);
            trainingSolo.setGoodRate(goodRate);
        }
        //达标率
        if (completeProgramNumber != 0 && qualifiedPersonNumber != 0) {
            BigDecimal qualifiedRate = new BigDecimal(qualifiedPersonNumber).divide(new BigDecimal(completeProgramNumber), 2, BigDecimal.ROUND_HALF_UP);
            trainingSolo.setQualifiedRate(qualifiedRate);
        }
        //不合格率
        if (completeProgramNumber != 0 && unqualifiedPersonNumber != 0) {
            BigDecimal unqualifiedRate = new BigDecimal(unqualifiedPersonNumber).divide(new BigDecimal(completeProgramNumber), 2, BigDecimal.ROUND_HALF_UP);
            trainingSolo.setUnqualifiedRate(unqualifiedRate);
        }
        trainingSoloRepository.create(trainingSolo);
        if (CollectionUtil.isNotEmpty(detailsList)) {
            soloDetailsRepository.saveBatch(detailsList);
        }
    }

    /**
     * 修改单人训练
     *
     * @param param
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void editTrainingSolo(EditTrainingSoloParam param) {
        Long id = param.getId();
        trainingSoloRepository.getByIdCheck(id);
        trainingSoloRepository.trueDeletion(id);

        soloDetailsRepository.getBaseMapper().selectList(new LambdaQueryWrapper<>(TrainingSoloDetails.class)
                        .eq(TrainingSoloDetails::getTrainingSoleId, id)
                        .eq(TrainingSoloDetails::getIsDelete, false))
                .forEach(soloDetails -> soloDetailsRepository.trueDeletion(soloDetails.getId()));

        createTrainingSolo(param);
    }


    /**
     * 移除单人训练
     *
     * @param id
     */
    @Override
    public void removeTrainingSolo(Long id) {
        trainingSoloRepository.removeById(id);
    }

    /**
     * 启动/禁用单人训练
     *
     * @param id
     */
    @Override
    public void enabledTrainingSolo(Long id) {
        TrainingSolo trainingSolo = trainingSoloRepository.getByIdCheck(id);
        trainingSolo.setIsDisable(!trainingSolo.getIsDisable());
        trainingSoloRepository.edit(trainingSolo);
    }

    /**
     * 获取单人训练详情
     *
     * @param id
     * @return
     */
    @Override
    public GetTrainingSoloVo getTrainingSolo(Long id) {
        TrainingSolo trainingSolo = trainingSoloRepository.getByIdCheck(id);
        GetTrainingSoloVo vo = new GetTrainingSoloVo();
        BeanUtils.copyProperties(trainingSolo, vo);
        vo.setUpdateTime(trainingSolo.getUpdateTime());

        User updateUser = userRepository.getById(trainingSolo.getUpdater());
        if (updateUser != null) {
            vo.setUpdateUserName(updateUser.getName());
        }
        User createUser = userRepository.getById(trainingSolo.getCreator());
        if (createUser != null) {
            vo.setCreateName(createUser.getName());
        }

        //缺训人员ids
        String absentPerson = trainingSolo.getAbsentPerson();
        if (absentPerson != null) {
            List<AbsentPersonParam> absentPersonParams = JSONArray.parseArray(absentPerson, AbsentPersonParam.class);
            for (AbsentPersonParam absentPersonParam : absentPersonParams) {
                PersonWarCase user = personWarCaseRepository.getById(absentPersonParam.getUserId());
                if (user != null) {
                    absentPersonParam.setUserName(user.getName());
                }
            }
            vo.setAbsentPerson(absentPersonParams);
        }

        //训练项目ids
        String programIds = trainingSolo.getProgramIds();
        if (programIds != null) {
            List<Long> programIdList = JSONArray.parseArray(programIds, Long.class);
            vo.setProgramIds(programIdList);
        }

        //训练成绩
        List<CreateTrainingSoloProgramParam> programParams = new ArrayList<>();
        List<TrainingSoloDetails> detailsList = soloDetailsRepository.getBaseMapper().selectList(
                new LambdaQueryWrapper<>(TrainingSoloDetails.class)
                        .eq(TrainingSoloDetails::getTrainingSoleId, id)
                        .eq(TrainingSoloDetails::getIsDelete, false));

        if (CollectionUtil.isNotEmpty(detailsList)) {
            //根据项目id分组
            Map<Long, List<TrainingSoloDetails>> trainingSoloDetails = detailsList.stream().collect(Collectors.groupingBy(TrainingSoloDetails::getTrainingProgramId));
            for (Map.Entry<Long, List<TrainingSoloDetails>> entry : trainingSoloDetails.entrySet()) {
                CreateTrainingSoloProgramParam programParam = new CreateTrainingSoloProgramParam();
                programParam.setTrainingProgramId(entry.getKey());

                TrainingProgram program = programRepository.getById(entry.getKey());
                if (program != null) {
                    programParam.setTrainingProgramName(program.getName());
                }

                List<CreateTrainingSoloDetailsParam> detailsParams = new ArrayList<>();
                for (TrainingSoloDetails details : entry.getValue()) {
                    CreateTrainingSoloDetailsParam detailsParam = new CreateTrainingSoloDetailsParam();
                    BeanUtils.copyProperties(details, detailsParam);

                    //用户名称
                    PersonWarCase user = personWarCaseRepository.getById(details.getUserId());
                    if (user != null) {
                        detailsParam.setUserName(user.getName());
                        detailsParam.setSex(user.getSex());
                        detailsParam.setAge(user.getAge());
                    }
                    detailsParams.add(detailsParam);
                }
                programParam.setTrainingSoloDetails(detailsParams);
                programParams.add(programParam);
            }
        }
        vo.setProgramParams(programParams);
        return vo;
    }

    /**
     * 获取单人训练 列表
     *
     * @param param
     * @return
     */
    @Override
    public PageResult<GetTrainingSoloListVo> getTrainingSoloList(GetTrainingSoloListParam param) {

        SelectTrainingSoloDto dto = new SelectTrainingSoloDto();
        BeanUtils.copyProperties(param, dto);
        Page<GetTrainingSoloListVo> page = trainingSoloRepository.selectTrainingSolo(dto);
        return new PageResult<>(page.getRecords(), page);

    }

    /**
     * 获取单人训练下拉列表
     *
     * @param param
     * @return
     */
    @Override
    public List<GetTrainingSoloDownListVo> getTrainingSoloDownList(GetTrainingSoloDownListParam param) {
        TrainingSolo po = new TrainingSolo();
        if (param != null) {
            BeanUtils.copyProperties(param, po);
        }
        List<TrainingSolo> trainingSoloList = trainingSoloRepository.getListByEntity(po);

        List<GetTrainingSoloDownListVo> list = new ArrayList<>();
        for (TrainingSolo trainingSolo : trainingSoloList) {
            GetTrainingSoloDownListVo vo = new GetTrainingSoloDownListVo();
            BeanUtils.copyProperties(trainingSolo, vo);
            list.add(vo);
        }
        return list;
    }

    /**
     * 根据人员id获取训练统计数量
     *
     * @param personId
     * @return
     */
    @Override
    public GetTrainingNumberVo getTrainingNumber(Long personId) {
        GetTrainingNumberVo vo = new GetTrainingNumberVo();
        //获取本月1号和下月1号
        LocalDate now = LocalDate.now();
        LocalDate firstDayOfMonth = now.withDayOfMonth(1);
        LocalDate firstDayOfNextMonth = now.plusMonths(1).withDayOfMonth(1);
        //获取本月的单人训练
        Long monthSoloTrainingCount = soloDetailsRepository.getBaseMapper().selectCount(new LambdaQueryWrapper<>(TrainingSoloDetails.class)
                .eq(TrainingSoloDetails::getUserId, personId)
                .eq(TrainingSoloDetails::getIsDelete, false)
                .ge(TrainingSoloDetails::getCreateTime, firstDayOfMonth)
                .lt(TrainingSoloDetails::getCreateTime, firstDayOfNextMonth));

        //获取本月的缺训量
        Long monthLackTrainingCount = trainingSoloRepository.getBaseMapper().selectCount(new LambdaQueryWrapper<>(TrainingSolo.class)
                .eq(TrainingSolo::getIsDelete, false)
                .eq(TrainingSolo::getStatus, 1)
                .ge(TrainingSolo::getCreateTime, firstDayOfMonth)
                .lt(TrainingSolo::getCreateTime, firstDayOfNextMonth)
                .like(TrainingSolo::getAbsentPersonUserIds, personId));

        //获取本月的小组训练量
        List<TrainingGroup> trainingGroups = groupRepository.getBaseMapper().selectList(new LambdaQueryWrapper<>(TrainingGroup.class)
                .eq(TrainingGroup::getIsDelete, false)
                .eq(TrainingGroup::getStatus, 1)
                .ge(TrainingGroup::getCreateTime, firstDayOfMonth)
                .lt(TrainingGroup::getCreateTime, firstDayOfNextMonth));
        Long monthGroupTrainingCount = 0L;
        if (CollectionUtil.isNotEmpty(trainingGroups)) {
            for (TrainingGroup trainingGroup : trainingGroups) {
                List<TrainingPerformanceParam> trainingPerformanceParams = JSONArray.parseArray(trainingGroup.getTrainingPerformance(), TrainingPerformanceParam.class);
                if (trainingPerformanceParams != null) {
                    for (TrainingPerformanceParam param : trainingPerformanceParams) {
                        if (param.getUserId().compareTo(personId) == 0) {
                            monthGroupTrainingCount = monthGroupTrainingCount + 1;
                        }
                    }
                }
            }
        }

        vo.setMonthSoloTrainingCount(monthSoloTrainingCount.intValue());
        vo.setMonthLackTrainingCount(monthLackTrainingCount.intValue());
        vo.setMonthGroupTrainingCount(monthGroupTrainingCount.intValue());
        return vo;
    }


}



